<!--
 * @Date: 2024-11-21 15:35:50
 * @Author: LiSong
 * @LastEditors: LiSong
 * @LastEditTime: 2025-03-14 09:19:23
 * @Description: 折线图
-->
<template>
  <div class="hp-chart-panel">
    <div class="hp-chart-panel-header">
      <div class="header-title">{{ schema.label }}</div>
      <div class="header-tools">
        <template v-if="chartState.radioOptions.length > 1">
          <el-radio-group v-model="chartState.type" >
            <el-radio-button v-for="item in chartState.radioOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-radio-group>
        </template>
      </div>
    </div>
    <div class="hp-chart-panel-body">
      <div
        ref="chartRef"
        class="chart-wrapper"
        :id="schema.id"
        v-hpresize="chartsHook.resizeChart"
      >
      </div>
    </div>
  </div>
</template>

<script setup>
import { isEmpty } from '@hp/utils/data.js';
import { commonProps } from '@hp/panels/cfg.js'
import { computed, onMounted, watch, nextTick, reactive } from 'vue';

import * as echarts from 'echarts';
import { useCharts } from '@hp/hooks/useCharts.js'
import { useDbSource } from '@hp/hooks/useDbSource.js'
import { useEventFunc } from '@hp/hooks/useEventFunc.js'


const emits = defineEmits([ 'mounted' ])
const props = defineProps({
  ...commonProps
})

// 图例通用操作
const chartsHook = useCharts({ ...props })
// 数据源相关操作
const dbsourceHook = useDbSource({ ...props })
// 事件函数相关操作
const eventFuncHook = useEventFunc({ ...props })

// 解构对象 chartMod-当前图例对象 chartRef-当前图例Ref
const { chartMod, chartRef } = chartsHook

// 图例数据
const chartState = reactive({
  // 当前维度类型
  type: '',
  // 分类数据
  kindData: {},
  // 维度数据
  typeData: {},
  // 请求数据
  respData: {},
  // 维度类型选项
  radioOptions: []
})
// 图例选项
const chartOption = computed(() => {
  const { schema } = props
  const baseOptions = loadBaseOption()
  const dataOptions = loadDataOption()

  let options = {
    ...baseOptions,
    ...dataOptions
  }
  if (schema.echarts.isX) {
    options.xAxis['type'] = 'value'
    options.yAxis['type'] = 'category'
    options.xAxis['boundaryGap'] = false
  } else {
    options.xAxis['type'] = 'category'
    options.yAxis['type'] = 'value'
  }
  return options
})

/**
 * 渲染图例组件
 */
const renderChart = async () => {
  chartMod.value = null;
  if (chartMod.value) chartMod.value.dispose()
  chartMod.value = echarts.init(chartRef.value)
  chartMod.value.showLoading();
  await loadData()
  setChartOption()
  initChartClick()
  chartMod.value.hideLoading();
}

/**
 * 初始化图例组件点击事件
 */
const initChartClick = () => {
  chartMod.value.on('click', function (data) {
    eventFuncHook.onClick(data, {
      otherData: chartState
    })
  })
}

/**
 * 设置图例的选项
 */
const setChartOption = () => {
  if (!chartMod.value) return
  chartMod.value.setOption(chartOption.value)
}
/**
 * 加载基础选项
 */
const loadBaseOption = () => {
  const { echarts } = props.schema
  const options = {
    grid: loadGridOption(),
    tooltip: echarts.tooltip,
  }
  return options
}
/**
 * 加载网格设置
 */
const loadGridOption = () => {
  const { grid } = props.schema.echarts
  const result = {}
  const percentKeys = ['top', 'left', 'right', 'bottom']
  Object.keys(grid).forEach(key => {
    if (percentKeys.includes(key)) {
      result[key] = `${grid[key]}%`
    } else {
      result[key] = grid[key]
    }
  })
  return result
}
/**
 * 加载存在数据集的选项
 */
const loadDataOption = () => {
  const { echarts } = props.schema
  const { legend, xAxis, yAxis } = echarts
  const aData = chartState.typeData[chartState.type]
  const kData = chartState.kindData[chartState.type]
  if (!kData || !aData) {
    return { legend, xAxis, yAxis, series: [] }
  } else {
    const axisData = aData[kData.labelKey]
    const legendData = kData.valueNames
    const seriesData = []
    kData.valueKeys.forEach(item => {
      const serieItem = {
        ...echarts.series,
        ...item,
        data: aData[item.field]
      }
      if (serieItem.isArea) {
        serieItem.areaStyle = {}
      } else {
        delete serieItem.areaStyle
      }
      seriesData.push(serieItem)
    })
    return {
      xAxis: { ...xAxis, data: axisData },
      yAxis: { ...yAxis, data: axisData },
      series: seriesData,
      legend: { ...legend, data: legendData },
    }
  }
}

/**
 * 将resData中的每个对象的key-value分离开,
 * 并将同名的key的value值组成一个数组
 * 
 * @param {array} resData - 需要分析的数据
 * @return {object} - 分析后的结果对象
 */
const analyseData = (resData) => {
  if (isEmpty(resData)) return {}
  let result = {}
  resData.forEach(item => {
    Object.keys(item).forEach(k => {
      if (!result[k]) {
        result[k] = [item[k]]
      } else {
        result[k].push(item[k])
      }
    })
  })
  return result
}

/**
 * 加载图例数据
 */
const loadData = async (params) => {
  if (props.schema.hasOwnProperty('dataList')) {
    await loadDataMultiple(params)
  } else {
    await loadDataSingle(params)
  }
}
/**
 * 重新加载数据
 * 
 * @param params 参数
 */
const reloadData = async (params) => {
  loadData(params)
}

/**
 * 加载单数据源的数据
 * 
 * @param {Object} params 额外参数
 */
const loadDataSingle = async (params) => {
  const { respResult, analyseResult } = await reqDataSourceSingle(params)
  chartState.respData = respResult
  chartState.typeData = analyseResult
  if (isEmpty(respResult)) return
  updateDataConfigSingle()
}
/**
 * 请求加载单数据源的数据
 * 
 * @param {Object} params 额外参数
 */
const reqDataSourceSingle = (params = {}) => {
  return new Promise(async (resolve, reject) => {
    let respResult = {}
    let analyseResult = {}
    const { id } = props.schema
    const res = await dbsourceHook.loadDataSource(props.schema, params)
    // 设置请求数据
    // respResult = res
    respResult[id] = res
    // 解析数据
    // analyseResult = analyseData(res)
    analyseResult[id] = analyseData(res)
    resolve({ respResult, analyseResult })
  })
}
/**
 * 更新单数据源的图表配置
 */
const updateDataConfigSingle = () => {
  const kResult = {}
  const options = []
  const { id, labelKey, valueKeys } = props.schema
  kResult[id] = {
    labelKey, valueKeys,
    valueNames: valueKeys.map(item => item.name) || []
  }
  chartState.type = id
  chartState.kindData = kResult
  chartState.radioOptions = options
  // console.log('updateDataConfigSingle', chartState)
}

/**
 * 加载多数据源
 * 
 * @param {Object} params 额外参数
 */
const loadDataMultiple = async (params) => {
  const { respResult, analyseResult } = await reqDataSourceMultiple(params)
  chartState.respData = respResult
  chartState.typeData = analyseResult
  if (isEmpty(respResult)) return
  updateDataConfigMultiple()
}

/**
 * 加载多数据源，请求获取数据
 * 
 * @param {Object} params 额外参数
 */
const reqDataSourceMultiple = (params={}) => {
  return new Promise(async (resolve, reject) => {
    const respResult = {}
    const analyseResult = {}
    const { dataList } = props.schema
    for (const dataItem of dataList) {
      const { id } = dataItem
      const res = await dbsourceHook.loadDataSource(dataItem, params)
      if (isEmpty(res)) continue
      // 设置请求数据
      respResult[id] = res
      // 解析数据
      analyseResult[id] = analyseData(res)
    }
    resolve({ respResult, analyseResult })
  })
}
/**
 * 更新多数据源时的图表配置
 */
const updateDataConfigMultiple = () => {
  const kResult = {}
  const options = []
  const { dataList } = props.schema
  dataList.forEach((dataItem, dataIndex) => {
    const { id, name } = dataItem
    if (dataIndex === 0) { chartState.type = id }
    let valueKeys = dataItem.valueKeys ||[]
    // 设置图例数据
    kResult[id] = {
      labelKey: dataItem.labelKey,
      valueKeys,
      valueNames: valueKeys.map(item => item.name) || []
    }
    // 设置分类数据
    options.push({ label: name, value: id })
  });
  chartState.kindData = kResult
  chartState.radioOptions = options
  // console.log('updateDataConfigMultiple', chartState)
}

onMounted(() => {
  nextTick(() => {
    emits('mounted')
    setTimeout(() => { renderChart() }, 200) }
  )
})

/*
  1 监听封装的数据集数据变化
  2 监听echarts的配置变化
*/
watch(
  [
    () => chartState,
    () => props.schema.echarts,
  ],
  () => {
    setChartOption()
  },
  { deep: true, immediate: false, effect: 'post' }
)

if (props.schema.hasOwnProperty('dataList')) {
  /*
    监听数据源配置变化
  */
  watch(
    () => props.schema.dataList.map(item => item.dataSource),
    (nv, ov) => {
      loadDataMultiple()
    },
    { deep: true, immediate: false }
  )
  /*
    监听数据配置变化（排除数据源）
  */
  watch(
    () => props.schema.dataList.map(item => {
      return {
        name: item.name,
        labelKey: item.labelKey,
        valueKeys: item.valueKeys
      }
    }),
    (nv, ov) => {
      updateDataConfigMultiple()
    },
    { deep: true, immediate: false }
  )
  
} else if (props.schema.hasOwnProperty('dataSource')) {
  watch(
    () => props.schema.dataSource,
    (nv, ov) => {
      loadDataSingle()
    },
    { deep: true, immediate: false }
  )
  watch(
    [
      () => props.schema.labelKey,
      () => props.schema.valueKeys
    ],
    (nv, ov) => {
      updateDataConfigSingle()
    },
    { deep: true, immediate: false }
  )
}

defineExpose({
  loadData,
  reloadData
})

</script>

<style lang="scss" scoped>
@use '@hp/panels/chart.scss' as *;
</style>